package com.linqi.freebie.http.ktorClientCio.interceptor

import io.github.aakira.napier.Napier
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.bodyAsText
import io.ktor.http.ContentType
import io.ktor.http.contentType
import io.ktor.util.AttributeKey
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement

class LogInterceptor(
    private val printBody: Boolean = false,      // 是否打印响应Body
    private val maxBodyLength: Int = 5000,       // Body最大打印长度
    private val isDebug: Boolean = true          // 是否启用日志
) : HttpInterceptor {

    override suspend fun onRequest(builder: HttpRequestBuilder) {
        if (!isDebug) return
        try {
            val method = builder.method.value
            val url = builder.url.toString()
            val headersMap = builder.headers.entries().associate { it.key to it.value }

            // 打印请求体（简单处理String类型）
            val requestBodyText = extractRequestBody(builder)

            Napier.d(
                """
                ┌── HTTP Request ─────────────────────────
                │ Method : $method
                │ URL    : $url
                │ Headers(${headersMap.size}): ${filterHeaders(headersMap)}
                ${if (printBody && requestBodyText.isNotEmpty()) "│ Body   : $requestBodyText" else ""}
                └──────────────────────────────────────────
                """.trimIndent(), tag = "HttpLog"
            )

            builder.attributes.put(HttpTimingKey, System.currentTimeMillis())
        } catch (e: Exception) {
            Napier.e("Exception in onRequest: ${e.message}", e, tag = "HttpLog")
        }
    }

    override suspend fun onResponse(response: HttpResponse) {
        if (!isDebug) return
        try {
            val url = response.call.request.url.toString()
            val status = response.status
            val headersMap = response.headers.entries().associate { it.key to it.value }

            val startTime = response.call.request.attributes[HttpTimingKey]
            val duration = System.currentTimeMillis() - startTime

            var safeBody = ""
            var bodyLines: List<String> = emptyList()
            if (printBody) {
                val bodyText = try {
                    response.bodyAsText()
                } catch (e: Exception) {
                    "无法读取 Body: ${e.message}"
                }
                val formattedBody = if (isJsonResponse(response)) prettyJson(bodyText) else bodyText
                safeBody = if (formattedBody.length > maxBodyLength) formattedBody.take(maxBodyLength) + "..." else formattedBody
                bodyLines = safeBody.lines()
            }

            val headersSize = headersMap.size

            val logMessage = buildString {
                appendLine("┌── HTTP Response ────────────────────────")
                appendLine("│ Status : $status")
                appendLine("│ URL    : $url")
                appendLine("│ Time   : ${duration}ms")
                appendLine("│ Headers($headersSize): ${filterHeaders(headersMap)}")
            }

            when (status.value) {
                in 200..299 -> Napier.d(logMessage, tag = "HttpLog")
                in 400..499 -> Napier.w(logMessage, tag = "HttpLog")
                in 500..599 -> Napier.e(logMessage, tag = "HttpLog")
                else -> Napier.i(logMessage, tag = "HttpLog")
            }

            if (printBody && safeBody.isNotEmpty()) {
                val oneLineContent = safeBody.replace(Regex("\\s+"), " ").trim()
                Napier.i("Content : $oneLineContent", tag = "HttpLog")
                /*bodyLines.forEach { line ->
                    Napier.d("│ $line", tag = "HttpLog")
                }*/
            }

            printEndLine()

        } catch (e: Exception) {
            Napier.e("Exception in onResponse: ${e.message}", e, tag = "HttpLog")
        }
    }

    private fun sanitizeHeaders(headers: Map<String, List<String>>): String {
        return headers.entries.joinToString {
            val key = it.key
            val value = if (key.lowercase() in listOf("authorization", "cookie")) "***" else it.value
            "$key=$value"
        }
    }

    private fun isJsonResponse(response: HttpResponse): Boolean {
        return response.contentType()?.match(ContentType.Application.Json) == true
    }

    private fun prettyJson(jsonString: String): String {
        return try {
            val jsonElement: JsonElement = Json.parseToJsonElement(jsonString)
            Json { prettyPrint = true; ignoreUnknownKeys = true }
                .encodeToString(JsonElement.serializer(), jsonElement)
        } catch (e: Exception) {
            jsonString
        }
    }

    private fun extractRequestBody(builder: HttpRequestBuilder): String {
        return try {
            val content = builder.body
            when (content) {
                is String -> {
                    val trimmed = content.trim()
                    if (trimmed.length > maxBodyLength) trimmed.take(maxBodyLength) + "..." else trimmed
                }
                else -> ""
            }
        } catch (e: Exception) {
            "无法读取请求Body: ${e.message}"
        }
    }

    companion object {
        val HttpTimingKey = AttributeKey<Long>("HttpTimingKey")
    }

    private fun filterHeaders(headers: Map<String, List<String>>): String {
        val keysToShow = listOf("Content-Type", "Content-Length", "Authorization", "Accept", "User-Agent")
        val filtered = headers.filter { (key, _) -> keysToShow.any { it.equals(key, ignoreCase = true) } }
        if (filtered.isEmpty()) return "{}"
        return filtered.entries.joinToString(", ") { "${it.key}=${it.value.joinToString()}" }
    }

    fun printEndLine() {
        Napier.d("╔════════════════════════════════════════════════════════════════════════════════════╗", tag = "HttpLog")
        Napier.d("║                            —— End of Response ——                                  ║", tag = "HttpLog")
        Napier.d("╚════════════════════════════════════════════════════════════════════════════════════╝", tag = "HttpLog")
    }
}
